#include"homogeneous.h"
HomogeneousMedium::HomogeneousMedium(const Spectrum &sigma_a, const Spectrum &sigma_s, PhaseFunction* p)
	:sigma_a(sigma_a), sigma_s(sigma_s), sigma_t(sigma_a + sigma_s), p(p) {}
Spectrum HomogeneousMedium::computeAttenuation(Ray &ray, Float t, Float *rands)
{
	t = min(t, INF);
	return Exp(-sigma_t * t);
}
Spectrum HomogeneousMedium::sampleMediumInteraction
(Ray &ray, Float next_surface_t, Float *sampled_t, RandGenerator *randGen)
{
	Float rands[] = { randGen->genRand() ,randGen->genRand() };
	//sample spectrum channel
	int channel = min(int(rands[0] * Spectrum::nSamples), Spectrum::nSamples - 1);
	//f(t) = exp(-sigma_t[channel]*t), sample t
	Float t = -log(1 - rands[1]) / sigma_t[channel];
	t = min(t, next_surface_t);
	*sampled_t = t;
	Spectrum Tr = computeAttenuation(ray, t, rands);
	//if t < ray distance to the next surface: sample medium
	//else sample surface
	bool sampleMedium = t < next_surface_t;
	Spectrum pd = sampleMedium ? (sigma_t*Tr) : Tr;
	Float pdf = 0;
	for (int i = 0; i < Spectrum::nSamples; ++i) pdf += pd[i];
	pdf *= 1 / (Float)Spectrum::nSamples;
	if (pdf == 0) pdf = 1; // potential problem: consider < eps
	return sampleMedium ? (Tr*sigma_s / pdf) : (Tr / pdf);

}
P3 HomogeneousMedium::sample_inScatterDir(P3 &pt, P3 &wo, Float *pdf, Float *rands)
{
	P3 wi;
	*pdf = p->sample_p(wo, &wi, rands);
	return wi;
}
Float HomogeneousMedium::scatterPdf(P3 &wo, P3 &wi)
{
	return p->p(wo, wi);
}